package itsm.isperp.module.service.app;

import itsm.isperp.framework.core.context.ContextHolder;
import itsm.isperp.framework.data.dialect.DialectFactory;
import itsm.isperp.framework.data.domain.DataResponse;
import itsm.isperp.framework.data.domain.PageResponse;
import itsm.isperp.framework.domain.IRole;
import itsm.isperp.framework.domain.IUser;
import itsm.isperp.framework.domain.UserStatus;
import itsm.isperp.framework.ldap.LdapContextUtils;
import itsm.isperp.framework.ldap.synchronize.UserSync;
import itsm.isperp.framework.security.encoding.DESHelper;
import itsm.isperp.framework.service.BaseService;
import itsm.isperp.framework.service.IUserService;
import itsm.isperp.framework.service.SyncUserDataService;
import itsm.isperp.framework.utils.HibernateUUIDGenerator;
import itsm.isperp.framework.web.request.JqGridFilterRuleOp;
import itsm.isperp.framework.web.request.JqGridRequest;
import itsm.isperp.framework.web.response.ResultMessage;
import itsm.isperp.module.dto.app.AppUserRoleDTO;
import itsm.isperp.module.dto.app.VAppDepartmentUser;
import itsm.isperp.module.entity.app.AppLdapConfig;
import itsm.isperp.module.entity.app.AppRole;
import itsm.isperp.module.entity.app.AppUser;
import itsm.isperp.module.entity.app.AppUserRole;
import itsm.isperp.module.repository.app.AppUserMapper;
import itsm.isperp.module.repository.app.AppUserRoleMapper;
import itsm.isperp.module.repository.app.VAppUserRoleMapper;
import itsm.isperp.module.service.project.ProjProjectService;
import itsm.isperp.module.utils.DbQueryUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.naming.NamingException;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.NullArgumentException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.jdbc.support.DatabaseType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

/**
 * 用户管理服务
 * 
 * @author lizx
 * @date 2013-2-17
 * @version V1.0
 */
@Service
public class AppUserService extends BaseService<AppUser> implements
		IUserService, UserDetailsService, SyncUserDataService {

	@Autowired
	protected AppUserMapper appUserMapper;

	@Autowired
	protected AppUserRoleMapper appUserRoleMapper;

	@Autowired
	protected VAppUserRoleMapper vAppUserRoleMapper;

	/*
	 * (non-Javadoc)
	 * 
	 * @see itsm.isperp.framework.service.BaseService#getRepository()
	 */
	@Override
	public AppUserMapper getRepository() {
		return this.appUserMapper;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * itsm.isperp.framework.service.BaseService#saveOrUpdate(itsm.isperp.framework
	 * .domain.IBean)
	 */
	@Override
	public int saveOrUpdate(AppUser entity) {
		if (StringUtils.isEmpty(entity.getId())) {
			entity.setId(HibernateUUIDGenerator.generate().toString());
			// 首先判断名字是否已经存在，然后在判断进行插入操作
		}
		AppUser user = this.getRepository().findByUsername(entity.getName());
		if (user == null)
			return this.getRepository().save(entity);
		else
			this.getRepository().update(entity);
		return 1;

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see itsm.isperp.framework.service.BaseService#delete(java.lang.String)
	 */
	@Override
	public ResultMessage delete(String id) {
		AppUser user = this.appUserMapper.findOne(id);
		if (user != null) {

			if (userHasRole(user.getName())) {
				return ResultMessage.failure("用户包含角色，不能删除！");
			}
			// 首先删除用户相关联的角色
			this.appUserRoleMapper.deleteByUsername(user.getName());
			this.appUserMapper.deleteByClass(id, AppUser.class);
		}

		return ResultMessage.success();
	}

	public boolean userHasRole(String username) {
		return DbQueryUtils
				.exists(AppUserRole.class, "app_user_name", username);
	}

	/**
	 * 删除除admin之外的所有用户
	 */
	@Override
	public void deleteAll() {
		JdbcTemplate jdbcTemplate = ContextHolder.getSpringBean("jdbcTemplate");
		jdbcTemplate.update("DELETE FROM app_user WHERE name<>'admin'");
	}

	/**
	 * 禁用所有用户
	 */
	public void disableAll() {
		JdbcTemplate jdbcTemplate = ContextHolder.getSpringBean("jdbcTemplate");
		jdbcTemplate.update("UPDATE app_user SET enable=0 WHERE name<>'admin'");
	}

	/**
	 * 保存或者更新某个帐号
	 * 
	 * @param appUserDTO
	 *            系统用户信息数据传输对象
	 */
	public void saveOrUpdateByAppUserDTO(AppUserRoleDTO appUserDTO)
			throws NullArgumentException {

		if (StringUtils.isEmpty(appUserDTO.getName())) {
			throw new NullArgumentException("用户名不能为空");
		}
		AppUser oldUser = this.appUserMapper.findByUsername(appUserDTO
				.getName());
		String id = HibernateUUIDGenerator.generate().toString();

		if (oldUser == null) {
			this.appUserMapper.saveByAppUserDTO(id, appUserDTO);
		} else {
			this.appUserMapper.updateByAppUserDTO(oldUser.getId(), appUserDTO);

			// 删除原有的角色信息
			this.appUserRoleMapper.deleteByUsername(appUserDTO.getName());
		}

		List<? extends IRole> roles = appUserDTO.getRoles();
		if (roles != null && roles.size() > 0) {
			String strSQL = "INSERT INTO app_user_role (id,app_user_name,app_role_id) VALUES(?,?,?)";

			JdbcTemplate jdbcTemplate = ContextHolder
					.getSpringBean("jdbcTemplate");
			List<Object[]> list = new ArrayList<>();

			for (IRole role : roles) {
				Object[] arg = new Object[3];
				arg[0] = HibernateUUIDGenerator.generate();
				arg[1] = appUserDTO.getName();
				arg[2] = role.getId();

				list.add(arg);
			}
			jdbcTemplate.batchUpdate(strSQL, list);
		}

	}

	/**
	 * 根据用户名获取用户数据传输对象，如果用户名为null则返回null对象，如果用户不存在则抛出异常
	 * {@link AppUserRoleDTO#AppUserDTO(AppUser)}
	 * 
	 * @param username
	 *            用户名
	 * @return 用户信息传输对象
	 */
	@SuppressWarnings("unchecked")
	public AppUserRoleDTO findMemberRoleEntityByUsername(String username) {

		if (StringUtils.isEmpty(username))
			return null;

		AppUserRoleDTO appUserDTO = new AppUserRoleDTO(
				this.appUserMapper.findByUsername(username));

		List<? extends AppRole> roles = this.vAppUserRoleMapper
				.findByUsername(username);

		appUserDTO.setRoles(roles);

		return appUserDTO;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * itsm.isperp.framework.service.IUserService#findMemberRolesByUsername(
	 * java.lang.String)
	 */
	@Override
	public List<? extends IRole> findMemberRolesByUsername(String username) {
		if (StringUtils.isEmpty(username))
			return null;

		return this.vAppUserRoleMapper.findByUsername(username);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * itsm.isperp.framework.service.IUserService#findByUsername(java.lang.String
	 * )
	 */
	@Override
	public AppUser findByUsername(String username, String... selectColumns) {
		return this.appUserMapper.findByUsername(username, selectColumns);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * itsm.isperp.framework.service.UserService#findByDeptId(java.lang.String)
	 */
	@Override
	public List<AppUser> findByDeptId(String deptId, String... selectColumns) {
		return this.appUserMapper.findAllByRequest(
				new JqGridRequest()
						.setSelectColumns(selectColumns)
						.isPageable(false)
						.addFilterRule("app_department_id",
								JqGridFilterRuleOp.eq, deptId)).getContent();
	}
	
	public List<AppUser> findUserByTopDeptIdByRequest(String deptId, String... selectColumns) {
		return this.appUserMapper.findUserByTopDeptIdByRequest(" b.treenode_path LIKE '%"+deptId+"%' ",
				new JqGridRequest()
						.setSelectColumns(selectColumns)
						.isPageable(false)
						).getContent();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * itsm.isperp.framework.service.UserService#findByPostion(java.lang.String)
	 */
	@Override
	public List<AppUser> findByPostion(String postion, String... selectColumns) {
		return this.appUserMapper.findAllByRequest(
				new JqGridRequest()
						.setSelectColumns(selectColumns)
						.isPageable(false)
						.addFilterRule("position", JqGridFilterRuleOp.eq,
								postion)).getContent();
	}

	/**
	 * 未实现/废弃的方法 UnsupportedOperationException
	 */
	@Override
	@Deprecated
	public List<AppUser> findByUserInfo(IUser userInfo) {
		throw new UnsupportedOperationException();
	}

	/**
	 * 保存用户及用户角色信息
	 * 
	 * @param model
	 *            {@link AppUser} 用户实体
	 * @param appUserDTO
	 *            {@link AppUserRoleDTO} 用户角色传输实体
	 */
	public void saveOrUpdate(AppUser model, AppUserRoleDTO appUserDTO,
			HttpServletRequest req) {

		JdbcTemplate jdbcTemplate = ContextHolder.getSpringBean("jdbcTemplate");
		if (StringUtils.isEmpty(model.getId())) {
			model.setId(HibernateUUIDGenerator.generate());
			model.setPassword(DESHelper.getDefualEncryptPassword());// 默认密码123456
			this.getRepository().save(model);
		} else {
			if (this.getRepository()
					.existsByClass(model.getId(), AppUser.class) == null) {
				// 默认密码123456
				model.setPassword(DESHelper.getDefualEncryptPassword());

				this.getRepository().save(model);
			} else {

				if (req.getParameterMap().containsKey("name")) {
					model.setPassword(DESHelper.getDefualEncryptPassword());
				}
				this.saveOrUpdate(model, req);
			}
		}

		if (DialectFactory.getDatabaseType() == DatabaseType.MYSQL) {
			jdbcTemplate
					.update("UPDATE app_user a  INNER JOIN cus_customer c ON a.customer_id=c.id SET customer_name=C.name WHERE a.id='"
							+ model.getId() + "'");
		} else {
			jdbcTemplate
					.update("UPDATE app_user a  SET customer_name=(SELECT name FROM  cus_customer c WHERE c.id=a.customer_id) WHERE a.id='"
							+ model.getId() + "'");
		}
		this.appUserRoleMapper.deleteByUsername(model.getUsername());
		List<? extends IRole> roles = appUserDTO.getRoles();
		if (roles != null && roles.size() > 0) {
			String strSQL = "INSERT INTO app_user_role (id,app_user_name,app_role_id) VALUES(?,?,?)";

			List<Object[]> list = new ArrayList<>();

			for (IRole role : roles) {
				Object[] arg = new Object[3];
				arg[0] = HibernateUUIDGenerator.generate();
				arg[1] = appUserDTO.getName();
				arg[2] = role.getId();

				list.add(arg);
			}
			jdbcTemplate.batchUpdate(strSQL, list);
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.security.core.userdetails.UserDetailsService#
	 * loadUserByUsername(java.lang.String)
	 */
	@Override
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException {
		AppUser u = this.appUserMapper.findByUsername(username);

		//
		Collection<? extends GrantedAuthority> auths = u.getAuthorities();
		if (auths == null || auths.isEmpty()) {
			List<? extends IRole> roles = this
					.findMemberRolesByUsername(username);
			u.setAuthorities(roles);
		}

		return u;
	}

	/**
	 * 获取部门用户视图数据返回
	 * 
	 * @param request
	 * @return
	 */
	public PageResponse<VAppDepartmentUser> getUserInRole(String roleId,
			JqGridRequest request) {
		return this.appUserMapper.findUserInRoleByRequest(roleId, request)
				.toPage();
	}

	/**
	 * 更新用户状态
	 * 
	 * @param status
	 *            用户状态
	 * @param username
	 *            用户帐号
	 */
	public void updateUserStatus(UserStatus status, String username) {
		this.appUserMapper.updateUserStatus(status.toString(), username);
	}

	/**
	 * 查询用户状态
	 * 
	 * @param loginUsername
	 *            用户帐号
	 * @return 用户状态
	 */
	public String findUserStatus(String loginUsername) {
		AppUser user = this.appUserMapper.findByUsername(loginUsername,
				"status");
		if (user == null) {
			return "用户不存在";
		}
		return user.getStatus();
	}

	/**
	 * 重置指定用户的密码
	 * 
	 * @param id
	 *            用户id
	 * @throws Exception
	 */
	public void restPassword(String id) throws Exception {
		AppUser user = new AppUser();
		user.setId(id);
		user.setPassword(DESHelper.getDefualEncryptPassword());

		Set<String> includeColumns = new HashSet<>();
		includeColumns.add("password");
		this.dynamicUpdateSpecific(user, includeColumns);
	}

	/**
	 * 根据用户帐号查询用户的详细信息
	 * 
	 * @param username
	 *            用户帐号
	 * @return 用户详细信息键值对
	 */
	public Map<String, Object> findOneDetailByUsername(String username) {
		JqGridRequest req = new JqGridRequest();
		req.isPageable(false);
		req.isQueryOne(true);
		req.addFilterRule("name", JqGridFilterRuleOp.eq, username);
		DataResponse<Map<String, Object>> result = this.getRepository()
				.findAllDetailByRequest(req);
		if (result == null || result.isEmpty()) {
			return null;
		}
		return result.get(0);

	}

	/**
	 * 修改用户信息，包括：姓名，email，手机，生日四个字段
	 * 
	 * @param user
	 *            用户信息
	 * @return 修改结果
	 */
	public ResultMessage changeUserInfo(AppUser user) {

		Set<String> includeColumns = new HashSet<>();
		includeColumns.add("fullname");
		includeColumns.add("email");
		includeColumns.add("mobile");
		includeColumns.add("birthday");
		this.saveOrUpdateSpecific(user, includeColumns);

		return ResultMessage.success();
	}

	/**
	 * 修改当前登录的后台用户的密码
	 * 
	 * @param oldPwd
	 *            旧密码
	 * @param newPwd
	 *            新密码
	 * @return 如果成功返回的ResultMessage.success为true，否则为false
	 * @throws Exception
	 */
	public ResultMessage changePassword(String oldPwd, String newPwd)
			throws Exception {

		IUser u = ContextHolder.getLoginUser();
		return changePassword(u, oldPwd, newPwd);
	}

	/**
	 * 修改用户密码
	 * 
	 * @param user
	 *            用户实体
	 * @param oldPwd
	 *            旧密码
	 * @param newPwd
	 *            新密码
	 * @return 如果成功返回的ResultMessage.success为true，否则为false
	 * @throws Exception
	 */
	public ResultMessage changePassword(IUser user, String oldPwd, String newPwd)
			throws Exception {

		String oldPwdStr1 = user.getPassword();

		String oldPwdStr2 = DESHelper.encrypt(oldPwd);
		if (oldPwdStr2.equals(oldPwdStr1)) {

			String newPwdStr = DESHelper.encrypt(newPwd);

			this.getRepository().updateUserPassword(user.getUsername(),
					newPwdStr);
			((AppUser) user).setPassword(newPwdStr);

			return ResultMessage.success();
		} else {
			return ResultMessage.failure("用户密码错误");
		}

	}

	/**
	 * 更新用户地理位置
	 * 
	 * @param username
	 *            用户帐号
	 * @param longitude
	 *            经度
	 * @param latitude
	 *            纬度
	 */
	public void updatePositionInfo(String username, String longitude,
			String latitude) {
		this.appUserMapper.updatePositionInfo(username, longitude, latitude);
	}

	/**
	 * 从ad域中同步用户数据
	 * 
	 * @throws NamingException
	 */
	@Override
	public void syncUserData() throws NamingException {

		AppLdapConfigService appLdapConfigService = ContextHolder
				.getSpringBean("appLdapConfigService");
		List<AppLdapConfig> list = appLdapConfigService.findAll();
		List<AppUser> users = new ArrayList<>();

		boolean sync = false;
		for (AppLdapConfig config : list) {
			if (StringUtils.isNotEmpty(config.getSystemOu())) {
				sync = true;
				users.addAll(UserSync.readSystemUserData(config.getDc(), config
						.getSystemOu(), config.getCustomerId(),
						LdapContextUtils.getLdapContext(config.getHost(),
								config.getPort(), config.getDc(),
								config.getAdUsername(), config.getAdPassword())));

			}
		}

		if (sync) {
			this.appUserMapper.updateAllEnable(false);
			for (AppUser u : users) {
				this.saveOrUpdate(u);
			}
		}

	}

	/**
	 * 批量保持用户
	 * 
	 * @param users
	 *            用户列表
	 */
	public void batchSave(List<AppUser> users) {
		for (AppUser u : users) {
			this.saveOrUpdate(u);
		}
	}

	/**
	 * 根据部门id及角色id获取所有相关的用户
	 * 
	 * @param departmentId
	 *            部门id
	 * @param roleId
	 *            角色id
	 * @return 用户列表
	 */
	public List<AppUser> findByDepartmentAndRoleId(String departmentId,
			String roleId) {
		return appUserRoleMapper.findRoleMembers(roleId, departmentId);

	}

	/**
	 * 根据用户id更新百度推送userid及channelId
	 * 
	 * @param id
	 *            唯一标识
	 * @param userId
	 *            百度userid
	 * @param channeld
	 *            设备唯一标识
	 */
	public void updatePushInfo(String id, String userId, String channelId,
			int deviceType) {
		JdbcTemplate jdbcTemplate = ContextHolder.getSpringBean("jdbcTemplate");
		jdbcTemplate.execute("UPDATE app_user SET user_id='" + userId
				+ "', channel_id ='" + channelId + "' WHERE id='" + id + "'");

	}

	/**
	 * 根据用户帐号查询用户 的百度的userid及channelid
	 * 
	 * @param username
	 *            用户帐号
	 * @return user_id及channel_id 作为key的一个键值对
	 */
	public Map<String, Object> findPushInfoByName(String username) {
		JdbcTemplate jdbcTemplate = ContextHolder.getSpringBean("jdbcTemplate");
		return jdbcTemplate
				.queryForMap("SELECT user_id,channel_id,device_type FROM app_user WHERE name='"
						+ username + "'");
	}

	/**
	 * 更新指定帐号的channel id 和 user id
	 * 
	 * @param username
	 *            用户帐号
	 * @param userId
	 *            百度userid
	 * @param channelId
	 *            百度 channelid
	 */
	public void updatePushInfoByUsername(String username, String userId,
			String channelId, int deviceType) {
		JdbcTemplate jdbcTemplate = ContextHolder.getSpringBean("jdbcTemplate");
		jdbcTemplate.execute("UPDATE app_user SET user_id='" + userId
				+ "', channel_id ='" + channelId + "',device_type="
				+ deviceType + " WHERE name='" + username + "'");

	}

	/**
	 * 获取用户关联的项目里列表
	 * 
	 * @param keyword
	 * @param pageable
	 * @return
	 */
	public List<Map<String, Object>> findUserProjects(String userId) {
		JqGridRequest req = new JqGridRequest();
		req.isPageable(false);
		req.addFilterRule("user_id", JqGridFilterRuleOp.eq, userId);
		req.setSelectColumns("id", "name", "cus_customer_id");

		req.addFilterRule("stage", JqGridFilterRuleOp.eq,
				ProjProjectService.STAGE_PUBLICED);

		return this.appUserMapper.findUserProjects(req);
	}

	public List<Map<String, Object>> findMembersProjectByUserId(String userId) {
		JdbcTemplate jdbcTemplate = ContextHolder.getSpringBean("jdbcTemplate");
		String sql = "SELECT distinct c.id ,c.name FROM proj_project_member a"
				+ " INNER JOIN app_user b ON a.app_user_name=b.name"
				+ " INNER JOIN proj_project c ON a.proj_project_id=c.id"
				+ " where b.id='" + userId + "'";
		return jdbcTemplate.queryForList(sql);
	}

	public AppUser findByOpenid(String openid, String... selectColumns) {
		JqGridRequest req = new JqGridRequest();
		req.isQueryOne(true);
		req.setSelectColumns(selectColumns);

		req.setSearchString("openid ='" + openid + "' OR name='" + openid + "'");

		return this.findOneByRequest(req);

	}

	public void updateOpenid(String id, String openid) {
		JdbcTemplate jdbcTemplate = ContextHolder.getSpringBean("jdbcTemplate");
		jdbcTemplate.update("UPDATE app_user SET openid=? WHERE  id=?", openid,
				id);
	}

	public void clearOpenid(String id) {
		JdbcTemplate jdbcTemplate = ContextHolder.getSpringBean("jdbcTemplate");
		jdbcTemplate.update("UPDATE app_user SET openid=null WHERE  id=?", id);

	}
	
	 public AppUser findByFullnameWithCustomerNameOrMobile(String fullname,String mobile,String customerName) {
	    JqGridRequest req = new JqGridRequest();
	    req.isQueryOne(true);
	    req.setSelectColumns("fullname","id","name");
	    req.setSearchString("fullname ='" + fullname + "' and (customer_name='" + customerName + "' or mobile='"+mobile+"')");
	    return this.findOneByRequest(req);
	  }

	public void updateUsername(String id, String accountId, String password)
			throws DataAccessException, Exception {
		JdbcTemplate jdbcTemplate = ContextHolder.getSpringBean("jdbcTemplate");
		jdbcTemplate.update(
				"UPDATE app_user SET name=?,password=? WHERE  id=?", id,
				accountId, DESHelper.encrypt(password));
	}
}
